package packing;



import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class State implements Serializable {

	private double evaluationScore;
	private double BastevaluationScore = 0;
	private String BastevaluationScoreText = "";
	private Container container = Container.getInstance();
	private List<Box> boxInputList;
	private List<BoxNode> conList = new ArrayList<BoxNode>();
	private String boxLine = "", statePosition = "";
	private int volume = 0;
	private String strBoxplaces = "";

	public State() {
		super();
		boxInputList = new ArrayList<Box>();
	}

	public State(Container container, List<Box> boxInputList) {
		super();
		this.container = container;
		this.boxInputList = boxInputList;
		evaluationScore = 0;
	}

	public Container getContainer() {
		return container;
	}

	public void setContainer(Container container) {
		this.container = container;
	}

	public List<Box> getBoxInputList() {
		return boxInputList;
	}

	public void setBoxInputList(List<Box> boxInputList) {
		this.boxInputList = boxInputList;
	}

	public void addBox(Box box) {
		this.boxInputList.add(box);
	}

	public double getEvaluationScore() {
		return evaluationScore;
	}

	public String evaluate() {
		String txt = "";
		for (BoxNode box : conList) {
			txt += box.toString();
		}
		evaluationScore = (double) volume / (double) container.getVolume();
		txt += "::: อัตราส่วนการใช้พื้นที่ : " + evaluationScore
				+ " ( Sum Volume Of Block(" + (double) volume
				+ ") / Volume Of Container(" + (double) container.getVolume()
				+ ") ) :::\n";
		return txt;

	}

	public void addState(Object object, int x, int y, int z) {
		BoxNode b = new BoxNode(object, x, y, z);
		conList.add(b);
	}

	public void removeState(Object object, int x, int y, int z) {
		BoxNode b = new BoxNode(object, x, y, z);
		conList.remove(b);
	}

	public boolean checkUseArea() {
		boolean a = false;
		boolean c = false;
		boolean e = false;
		boolean chk = true;
		for (int i = 0; i < conList.size(); i++) {
			for (int j = 0; j < conList.size(); j++) {
				if (j != i) {
					String[] tmp1 = conList.get(j).useArea().split(",");
					String[] tmp2 = conList.get(i).useArea().split(",");
					if (Integer.parseInt(tmp1[0]) == Integer.parseInt(tmp2[0])
							&& Integer.parseInt(tmp1[1]) == Integer
									.parseInt(tmp2[1])
							&& Integer.parseInt(tmp1[2]) == Integer
									.parseInt(tmp2[2])
							&& Integer.parseInt(tmp1[3]) == Integer
									.parseInt(tmp2[3])
							&& Integer.parseInt(tmp1[4]) == Integer
									.parseInt(tmp2[4])
							&& Integer.parseInt(tmp1[5]) == Integer
									.parseInt(tmp2[5])) {
						return false;
					}

					a = (Integer.parseInt(tmp1[0]) > Integer.parseInt(tmp2[0]) && Integer
							.parseInt(tmp1[0]) < Integer.parseInt(tmp2[1]))
							|| (Integer.parseInt(tmp1[1]) > Integer
									.parseInt(tmp2[0]) && Integer
									.parseInt(tmp1[1]) < Integer
									.parseInt(tmp2[1]));

					c = (Integer.parseInt(tmp1[2]) > Integer.parseInt(tmp2[2]) && Integer
							.parseInt(tmp1[2]) < Integer.parseInt(tmp2[3]))
							|| (Integer.parseInt(tmp1[3]) >= Integer
									.parseInt(tmp2[2]) && Integer
									.parseInt(tmp1[3]) < Integer
									.parseInt(tmp2[3]));

					e = (Integer.parseInt(tmp1[4]) >= Integer.parseInt(tmp2[4]) && Integer
							.parseInt(tmp1[4]) < Integer.parseInt(tmp2[5]))
							|| (Integer.parseInt(tmp1[5]) >= Integer
									.parseInt(tmp2[4]) && Integer
									.parseInt(tmp1[5]) < Integer
									.parseInt(tmp2[5]));

				}
			}
			if (a && c && e) {
				chk = false;
				break;
			}
		}
		return chk;
	}

	public String getState(int size) {
		String tmp = "";
		int type = 1;
		Box[][][] box = container.createContianner(size);
		for (BoxNode b : conList) {
			box[b.x][b.y][b.z] = b.box;
		}
		try {
			for (BoxNode nb : conList) {
				int useX = 0, useY = 0, useZ = 0;
				if (nb.z != 0) {
					for (int i = nb.z - 1; i >= 0; i--) {
						useZ += box[nb.x][nb.y][i].height;
					}
				}
				if (nb.y != 0) {
					for (int i = nb.y - 1; i >= 0; i--) {
						useY += box[nb.x][i][nb.z].width;
					}
				}
				if (nb.x != 0) {
					for (int i = nb.x - 1; i >= 0; i--) {
						useX += box[i][nb.y][nb.z].length;
					}
				}
				nb.setPositionX(useX);
				nb.setPositionY(useY);
				nb.setPositionZ(useZ);
				tmp += nb.box.id + " (" + useX + "," + useY + "," + useZ + ") ";
				strBoxplaces += nb.box.getLength() + " " + nb.box.getWidth()
						+ " " + nb.box.getHeight() + " " + useX + " " + useY
						+ " " + useZ + " " + (type++) + "\n";
			}
		} catch (Exception e) {

		}
		return tmp;
	}

	public void addAllBox(List<BoxNode> box) {
		this.conList.addAll(box);
	}

	public List<BoxNode> getAllBox() {
		return conList;
	}

	public void sortBox() {
		for (int i = 0; i < conList.size(); i++) {
			for (int j = i + 1; j < conList.size(); j++) {
				if (conList.get(i).getPoint() > conList.get(j).getPoint()) {
					BoxNode b = conList.get(i);
					conList.set(i, conList.get(j));
					conList.set(j, b);
				}
			}
		}
	}

	public boolean checkNode() {
		if (conList.get(0).x == 0 && conList.get(0).y == 0
				&& conList.get(0).z == 0) {
			return true;
		} else {
			return false;
		}
	}

	public boolean checkNextBox() {
		String x = "0";
		String y = "0";
		String z = "0";
		boxLine = "";
		boolean chk = true;
		for (int i = 0; i < conList.size(); i++) {
			int cx = conList.get(i).x;
			int cy = conList.get(i).y;
			int cz = conList.get(i).z;
			if (i != 0) {
				if (x.indexOf(Integer.toString(cx - 1)) > -1
						&& y.indexOf(Integer.toString(cy)) > -1
						&& z.indexOf(Integer.toString(cz)) > -1) {
					x += Integer.toString(cx);
					boxLine += "/"
							+ conList.get(i).box.getId()
							+ "-InFont("
							+ checkBeforeBox((conList.get(i).x - 1),
									conList.get(i).y, conList.get(i).z) + ")";
					chk = true;
				} else if (x.indexOf(Integer.toString(cx)) > -1
						&& y.indexOf(Integer.toString(cy - 1)) > -1
						&& z.indexOf(Integer.toString(cz)) > -1) {
					y += Integer.toString(cy);
					boxLine += "/"
							+ conList.get(i).box.getId()
							+ "-Left("
							+ checkBeforeBox((conList.get(i).x),
									(conList.get(i).y - 1), conList.get(i).z)
							+ ")";
					chk = true;
				} else if (x.indexOf(Integer.toString(cx)) > -1
						&& y.indexOf(Integer.toString(cy)) > -1
						&& z.indexOf(Integer.toString(cz - 1)) > -1) {
					z += Integer.toString(cz);
					boxLine += "/"
							+ conList.get(i).box.getId()
							+ "-Top("
							+ checkBeforeBox((conList.get(i).x),
									conList.get(i).y, (conList.get(i).z - 1))
							+ ")";
					chk = true;
				} else {
					chk = false;
					break;
				}
			} else {
				boxLine += conList.get(i).box.getId();
			}
		}
		System.out.println(boxLine +" is "+chk);
		return chk;
	}

	public String checkBeforeBox(int x, int y, int z) {
		String box = "";
		for (BoxNode b : conList) {
			if (b.x == x && b.y == y && b.z == z) {
				box = b.box.getId();
				break;
			}
		}
		return box;
	}

	public String getBoxLine() {
		return boxLine;
	}

	public void setBoxLine(String boxLine) {
		this.boxLine = boxLine;
	}

	public boolean calculateZ(int size) {
		List<Box> pressure = new ArrayList<Box>();
		int height = 0, max = 0;
		Box[][][] box = container.createContianner(size);
		for (BoxNode b : conList) {
			box[b.x][b.y][b.z] = b.box;
		}
		for (int x = 0; x < size; x++) {
			for (int y = 0; y < size; y++) {
				height = 0;
				for (int z = 0; z < size; z++) {
					if (box[x][y][z] != null) {
						height += box[x][y][z].height;
						pressure.add(box[x][y][z]);
					} else {
						break;
					}
				}
				if (max < height) {
					max = height;
				}
				if (!calculatePressure(pressure)) {
					return false;
				}
				pressure.clear();

			}

		}
		if (max > container.height) {
			return false;
		} else {
			return true;
		}
	}

	public boolean calculatePressure(List<Box> box) {
		for (int i = 0; i < box.size(); i++) {
			int weight = 0;
			int pressure = box.get(i).getPressure();
			for (int j = i + 1; j < box.size(); j++) {
				weight += box.get(j).getWeight();
			}
			if (pressure < weight) {
				return false;
			}
		}
		return true;

	}

	public boolean calculateX(int size) {
		int width = 0, max = 0;
		Box[][][] box = container.createContianner(size);
		for (BoxNode b : conList) {
			box[b.x][b.y][b.z] = b.box;
		}
		for (int y = 0; y < size; y++) {
			for (int z = 0; z < size; z++) {
				width = 0;
				for (int x = 0; x < size; x++) {
					if (box[x][y][z] != null) {
						width += box[x][y][z].length;
					} else {
						break;
					}
				}
				if (max < width) {
					max = width;
				}
			}

		}
		if (max > container.length) {
			return false;
		} else {
			return true;
		}
	}

	public boolean calculateY(int size) {
		int length = 0, max = 0;
		Box[][][] box = container.createContianner(size);
		for (BoxNode b : conList) {
			box[b.x][b.y][b.z] = b.box;
		}
		for (int z = 0; z < size; z++) {
			for (int x = 0; x < size; x++) {
				length = 0;
				for (int y = 0; y < size; y++) {
					if (box[x][y][z] != null) {
						length += box[x][y][z].width;
					} else {
						break;
					}
				}
				if (max < length) {
					max = length;
				}
			}

		}
		if (max > container.width) {
			return false;
		} else {
			return true;
		}
	}

	public int getVolume() {
		for (BoxNode box : conList) {
			volume += box.box.getVolume();
		}
		return volume;
	}

	public double getPoint() {
		double point = 0;
		for (int i = 0; i < conList.size(); i++) {
			point += conList.get(i).box.getVolume() / (i + 1);
		}
		return point;
	}

	public String getStrBoxplaces() {
		return strBoxplaces;
	}
	public boolean sortByPressure(){
		for (int i = 0; i < conList.size(); i++) {
			BoxNode current = conList.get(i);
			int base = current.box.pressure;
			if (base == 0) {
				continue;
			}
			int totalWeight = 0;
			for (int j = 0; j < conList.size(); j++) {
				if (!isValidPosition(current, conList.get(j), true)) {
					totalWeight += conList.get(j).box.weight;
				}
			}
			if (base < totalWeight) {
				return false;
			}
		}
		return true;
	}
	public boolean isValidPosition(BoxNode b1,BoxNode b2,boolean chk){
		int positionX1 = b1.positionX;
		int positionY1 = b1.positionY;
		int positionZ1 = b1.positionZ;
		int positionX2 = b2.positionX;
		int positionY2 = b2.positionY;
		int positionZ2 = b2.positionZ;
		if(chk){
			if(positionX1 == positionX2 || positionY1 == positionY2){
				if(positionZ1 < positionZ2){
					return false;
				}
			}
		} else {
			if (positionZ1 < positionZ2 || positionZ1 > positionZ2){
				if(positionX1 == positionX2 && positionY1 == positionY2){
					return true;
				} else {
					return false;
				}
			}
			
		}
		
		return true;
	}
}

